using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using BodySoundSimulator.AbsoluteMapData;
using System.IO;
using System.Xml.Serialization;
using BodySoundSimulator.CaseData;
using NAudio.Wave;
using System.Collections.ObjectModel;
using BodySoundSimulator.CommonElements;

namespace BodySoundSimulator.Recording
{
    public partial class Recorder : UserControl
    {
        #region Drawing related constants
        Pen p = new Pen(Color.Black);
        int originTranslateX = 150;
        int originTranslateY = 100;
        #endregion

        #region Fileds
        CaseInformation caseInfo;
        AuscultationSiteInfo selectedSiteInfo = null;

        IWaveIn waveIn;
        WaveFileWriter writer;
        string outputFilename;
        IApplicationServices appServices;
        #endregion

        #region Constructors
        public Recorder(IApplicationServices services)
        {
            InitializeComponent();
            LoadAllComboBoxes();
            this.pnlRecorderMain.Enabled = false;
            this.appServices = services;
        }
        #endregion

        #region public methods
        #endregion

        #region Private methods
        private PointF TranslateCoordinates(float x, float y)
        {
            return new PointF(x - originTranslateX, y - originTranslateY);
        }

        private void UpdateAuscultationSiteInfoRecorderUI()
        {
            if (this.selectedSiteInfo != null)
            {
                this.pnlSiteInfo.Enabled = true;
                this.cmbConfiguration.Enabled = true;
                string soundFileName = Path.Combine(Application.StartupPath, Path.Combine(Path.Combine(SimulatorFileManager.CasesFolderName, SimulatorFileManager.GetCaseTempFolderName(this.caseInfo.CaseID)), SimulatorFileManager.GetSoundFileName(this.caseInfo.CaseID, this.selectedSiteInfo, (AuscultationConfiguration)((ComboBoxItem)this.cmbConfiguration.SelectedItem).Tag)));
                if (!File.Exists(soundFileName))
                {
                    soundFileName = "Not Existing";
                    this.btnListen.Enabled = false;
                }
                else
                {
                    this.btnListen.Enabled = true;
                }
                this.txtAuscultationSiteInformation.Text = string.Format(SimulatorFileManager.GetInfoString("AuscultationSiteDisplayInfo.txt"),
                    this.selectedSiteInfo.Location.X,
                    this.selectedSiteInfo.Location.Y,
                    soundFileName);
            }
            else
            {
                this.btnListen.Enabled = false;
                this.cmbConfiguration.Enabled = false;
                this.txtAuscultationSiteInformation.Text = string.Empty;
            }
        }

        private void LoadAllComboBoxes()
        {
            this.cmbConfiguration.Items.Add(new ComboBoxItem("NormalBreath", AuscultationConfiguration.NormalBreath));
            this.cmbConfiguration.Items.Add(new ComboBoxItem("RapidBreath", AuscultationConfiguration.RapidBreath));
            this.cmbConfiguration.Items.Add(new ComboBoxItem("BreathUp", AuscultationConfiguration.BreathUp));
            this.cmbConfiguration.Items.Add(new ComboBoxItem("BreathDown", AuscultationConfiguration.BreathDown));
            this.cmbConfiguration.SelectedIndex = 0;
        }

        private void UpdateUI()
        {
            this.picBoxFrontView.Invalidate();
            this.picBoxBackView.Invalidate();
            this.txtCaseID.Text = this.caseInfo.CaseID;
            this.txtDetails.Text = this.caseInfo.PatientsClaim;
            this.txtDiseaseName.Text = this.caseInfo.DiseaseName;
            this.txtSoundName.Text = this.caseInfo.SoundName;
            UpdateAuscultationSiteInfoRecorderUI();
        }

        private void StartRecording()
        {
            if (waveIn == null)
            {
                waveIn = new WaveIn();
                waveIn.WaveFormat = new WaveFormat(8000, 1);

                outputFilename = SimulatorFileManager.GetSoundFileName(this.caseInfo.CaseID, this.selectedSiteInfo, (AuscultationConfiguration)((ComboBoxItem)this.cmbConfiguration.SelectedItem).Tag);
                writer = new WaveFileWriter(Path.Combine(Application.StartupPath, Path.Combine(Path.Combine(SimulatorFileManager.CasesFolderName, SimulatorFileManager.GetCaseTempFolderName(this.caseInfo.CaseID)), outputFilename)), waveIn.WaveFormat);

                waveIn.DataAvailable += new EventHandler<WaveInEventArgs>(waveIn_DataAvailable);
                waveIn.RecordingStopped += new EventHandler(waveIn_RecordingStopped);
                waveIn.StartRecording();
            }
        }

        private void StopRecording()
        {
            waveIn.StopRecording();
        }

        private void waveIn_RecordingStopped(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new EventHandler(waveIn_RecordingStopped), sender, e);
            }
            else
            {
                waveIn.Dispose();
                waveIn = null;
                writer.Close();
                writer = null;
            }
        }

        private void waveIn_DataAvailable(object sender, WaveInEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new EventHandler<WaveInEventArgs>(waveIn_DataAvailable), sender, e);
            }
            else
            {
                writer.WriteData(e.Buffer, 0, e.BytesRecorded);
                int secondsRecorded = (int)(writer.Length / writer.WaveFormat.AverageBytesPerSecond);
            }
        }

        private void CreateCaseInFolder(CaseInformation caseInfo)
        {
            string casesFolderPath = Path.Combine(Application.StartupPath, SimulatorFileManager.CasesFolderName);
            string path = Path.Combine(Application.StartupPath, Path.Combine(casesFolderPath, SimulatorFileManager.GetCaseTempFolderName(caseInfo.CaseID)));
            try
            {
                if (!Directory.Exists(casesFolderPath))
                {
                    Directory.CreateDirectory(casesFolderPath);
                }
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        private void SelectConfigurationComboBoxItem(ComboBox comboBox, AuscultationConfiguration configuration)
        {
            foreach (object item in comboBox.Items)
            {
                ComboBoxItem comboBoxItem = item as ComboBoxItem;
                if ((AuscultationConfiguration)comboBoxItem.Tag == configuration)
                {
                    comboBox.SelectedItem = item;
                }
            }
        }

        #endregion

        #region UI event handlers
        private void picBoxFrontView_Paint(object sender, PaintEventArgs e)
        {
            if (this.caseInfo != null)
            {
                Graphics g = e.Graphics;
                g.TranslateTransform(originTranslateX, originTranslateY);
                AbsoluteBodyFeaturesDataManipulator.DrawFrontView(g, this.appServices.AbsoluteFeatures);
                AuscultationSiteInfoManipultor.DrawFrontViewCaseInfo(g, this.caseInfo, this.selectedSiteInfo);
            }
        }

        private void picBoxBackView_Paint(object sender, PaintEventArgs e)
        {
            if (this.caseInfo != null)
            {
                Graphics g = e.Graphics;
                g.TranslateTransform(originTranslateX, originTranslateY);
                AbsoluteBodyFeaturesDataManipulator.DrawBackView(g, this.appServices.AbsoluteFeatures);
                AuscultationSiteInfoManipultor.DrawBackViewCaseInfo(g, this.caseInfo, this.selectedSiteInfo);
            }
        }

        private void chkAddNewSite_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void picBoxFrontView_MouseMove(object sender, MouseEventArgs e)
        {
            if (this.caseInfo != null)
            {
                PointF mousePoint = TranslateCoordinates(e.X, e.Y);
                if (AuscultationSiteInfoManipultor.IsPointOnSite(mousePoint, this.caseInfo, PatientView.FrontView))
                {
                    this.picBoxFrontView.Cursor = Cursors.Hand;
                }
                else
                {
                    this.picBoxFrontView.Cursor = Cursors.Arrow;
                }
            }
        }

        private void picBoxFrontView_MouseDown(object sender, MouseEventArgs e)
        {
            if (this.caseInfo != null)
            {
                PointF mousePoint = TranslateCoordinates(e.X, e.Y);
                AuscultationSiteInfo siteInfo = null;
                if (AuscultationSiteInfoManipultor.IsPointOnSite(mousePoint, this.caseInfo, PatientView.FrontView, ref siteInfo))
                {
                    this.selectedSiteInfo = siteInfo;
                }
                else
                {
                    this.selectedSiteInfo = null;
                }
                this.picBoxFrontView.Invalidate();
                UpdateAuscultationSiteInfoRecorderUI();
            }
        }

        private void btnNewCase_Click(object sender, EventArgs e)
        {
            NewCase newCaseDialog = new NewCase(this.appServices.ExistingCases);
            if (newCaseDialog.ShowDialog() == DialogResult.OK)
            {
                this.selectedSiteInfo = null;
                this.caseInfo = new CaseInformation();
                this.caseInfo.LoadBasicLungAndHeartAuscultationSites();
                this.caseInfo.CaseID = newCaseDialog.CaseID;
                this.caseInfo.PatientsClaim = newCaseDialog.Details;
                this.caseInfo.SoundName = newCaseDialog.SoundName;
                this.caseInfo.DiseaseName = newCaseDialog.DiseaseCondition;
                try
                {
                    CreateCaseInFolder(this.caseInfo);
                    this.pnlRecorderMain.Enabled = true;
                    this.caseInfo.XmlSerialize(Path.Combine(Application.StartupPath, Path.Combine(Path.Combine(SimulatorFileManager.CasesFolderName, SimulatorFileManager.GetCaseTempFolderName(this.caseInfo.CaseID)), SimulatorFileManager.GetMapFileName(this.caseInfo.CaseID))));
                    this.appServices.ExistingCaseListChanged();
                    UpdateUI();
                }
                catch (Exception exp)
                {
                    MessageBox.Show(string.Format("Case information loading failed./nReason/n{0}", exp.Message), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void btnStartRecording_Click(object sender, EventArgs e)
        {
            if (selectedSiteInfo != null)
            {
                this.btnStartRecording.Visible = false;
                this.btnStopRecording.Visible = true;
                //auscultation site is selected start recording sound from microphone
                StartRecording();
            }
        }

        private void btnStopRecording_Click(object sender, EventArgs e)
        {
            if (waveIn != null)
            {
                this.btnStartRecording.Visible = true;
                this.btnStopRecording.Visible = false;

                //stop recording and assign filename to the selected auscultaiton site
                StopRecording();
                UpdateAuscultationSiteInfoRecorderUI();
            }
        }

        private void cmbConfiguration_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateAuscultationSiteInfoRecorderUI();
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            LoadCaseDialog caseLoadingDialog = new LoadCaseDialog(this.appServices.ExistingCases);
            if (caseLoadingDialog.ShowDialog() == DialogResult.OK)
            {
                this.selectedSiteInfo = null;
                this.caseInfo = caseLoadingDialog.SelectedCaseInfo;
                this.pnlRecorderMain.Enabled = true;
                UpdateUI();
            }
        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            string soundFileName = Path.Combine(Application.StartupPath, Path.Combine(Path.Combine(SimulatorFileManager.CasesFolderName, SimulatorFileManager.GetCaseTempFolderName(this.caseInfo.CaseID)), SimulatorFileManager.GetSoundFileName(this.caseInfo.CaseID, this.selectedSiteInfo, (AuscultationConfiguration)((ComboBoxItem)this.cmbConfiguration.SelectedItem).Tag)));
            SimpleWavePlayer player = new SimpleWavePlayer(soundFileName);
            player.ShowDialog();
        }
        #endregion
    }
}
